package com.scheduling.schedule.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.scheduling.order.entity.Order;
import com.scheduling.order.entity.OrderItem;
import com.scheduling.order.mapper.OrderItemMapper;
import com.scheduling.product.entity.Operation;
import com.scheduling.schedule.entity.WorkOrder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 工单生成服务
 * 负责根据订单和不同的排产策略生成工单
 *
 * @author 开发团队
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class WorkOrderGenerationService {

    private final OrderItemMapper orderItemMapper;
    private final ScheduleDataService scheduleDataService;

    /**
     * 默认工单生成策略（FIFO）
     * 按订单项直接转换为工单
     */
    //除了集中生产算法，其他算法都直接（FIFO和遗传）或间接使用默任订单项直接转为工单的方法，
    // 关键路径算法中使用到下述紧急订单优先生成方法，但只是用订单的状态枚举字段（1.2.3）排序后用默认生成工单的方法，
    // Combine中是先根据截至时间的计算出紧急程度在以此排序，排序后再使用默认生成工单的方法，与关键路径的区别在于紧急度的判别
    // 机器利用率最大的工单生成方法也是调用的默认方法，然后按工作量排序
    public List<WorkOrder> generateDefaultWorkOrders(List<Order> orders, LocalDateTime scheduleStartTime) {
        log.debug("使用默认策略生成工单，订单数量: {}", orders.size());

        List<WorkOrder> workOrders = new ArrayList<>();
        AtomicInteger workOrderSequence = new AtomicInteger(1);
        String timeStamp = String.valueOf(System.currentTimeMillis()).substring(7); // 使用毫秒时间戳后6位

        for (Order order : orders) {
            try {
                // 获取订单项
                LambdaQueryWrapper<OrderItem> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(OrderItem::getOrderId, order.getOrderId());
                List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);

                for (OrderItem orderItem : orderItems) {
                    int remaining = orderItem.getQuantity();
                    int batchCount = 1;
                    while (remaining > 0) {
                        int batchSize = Math.min(remaining, 1000); // 拆分阈值为1000（产品数量）
                        WorkOrder workOrder = new WorkOrder();
                        workOrder.setWorkOrderId("WO" + timeStamp +
                                String.format("%03d", workOrderSequence.getAndIncrement()));
                        workOrder.setOrderItemId(orderItem.getOrderItemId());
                        workOrder.setProductId(orderItem.getProductId());
                        workOrder.setQuantity(batchSize);
                        workOrder.setPriority(orderItem.getPriority());
                        workOrder.setStatus("已排产");
                        workOrder.setPlanStartTime(scheduleStartTime);
                        workOrder.setPlanEndTime(convertToLocalDateTime(order.getDueDate()));
                        workOrder.setCreateTime(LocalDateTime.now());
                        workOrder.setUpdateTime(LocalDateTime.now());

                        workOrders.add(workOrder);

                        remaining -= batchSize;
                        batchCount++;
                        log.debug("生成拆分工单: {} - 产品: {}, 数量: {}/{}, 批次: {}",
                                workOrder.getWorkOrderId(), orderItem.getProductId(),
                                batchSize, orderItem.getQuantity(), batchCount - 1);
                    }
                }
            } catch (Exception e) {
                log.error("为订单 {} 生成工单失败: {}", order.getOrderId(), e.getMessage());
            }
        }
        log.info("默认策略生成工单完成，总数: {}", workOrders.size());
        return workOrders;
    }

    /**
     * 紧急优先工单生成策略
     * 按优先级重新组织订单项，可能拆分或合并
     */
    public List<WorkOrder> generateUrgentPriorityWorkOrders(List<Order> orders, LocalDateTime scheduleStartTime) {
        log.debug("使用紧急优先策略生成工单，订单数量: {}", orders.size());

        List<WorkOrder> workOrders = new ArrayList<>();
        AtomicInteger workOrderSequence = new AtomicInteger(1);
        String timeStamp = String.valueOf(System.currentTimeMillis()).substring(7); // 使用毫秒时间戳后6位

        // 收集所有订单项并按优先级排序
        List<OrderItem> allOrderItems = new ArrayList<>();
        for (Order order : orders) {
            try {
                LambdaQueryWrapper<OrderItem> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(OrderItem::getOrderId, order.getOrderId());
                List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);
                allOrderItems.addAll(orderItems);
            } catch (Exception e) {
                log.error("获取订单 {} 的订单项失败: {}", order.getOrderId(), e.getMessage());
            }
        }

        // 按优先级排序（数字越小优先级越高）
        allOrderItems.sort((item1, item2) -> {
            int priority1 = item1.getPriority() != null ? item1.getPriority() : 999;
            int priority2 = item2.getPriority() != null ? item2.getPriority() : 999;

            int priorityCompare = Integer.compare(priority1, priority2);
            if (priorityCompare != 0) {
                return priorityCompare;
            }

            // 优先级相同时按订单的截止时间排序
            Order order1 = findOrderByItemId(orders, item1.getOrderItemId());
            Order order2 = findOrderByItemId(orders, item2.getOrderItemId());

            if (order1 != null && order2 != null &&
                    order1.getDueDate() != null && order2.getDueDate() != null) {
                return order1.getDueDate().compareTo(order2.getDueDate());
            }

            return 0;
        });

        // 生成工单
        for (OrderItem orderItem : allOrderItems) {
            Order parentOrder = findOrderByItemId(orders, orderItem.getOrderItemId());
            int remaining = orderItem.getQuantity();
            int batchCount = 1;

            while (remaining > 0) {
                int batchSize = Math.min(remaining, 1000); // 拆分阈值为1000（产品数量）
                WorkOrder workOrder = new WorkOrder();
                workOrder.setWorkOrderId("WOU" + timeStamp + String.format("%03d",
                        workOrderSequence.getAndIncrement()));
                workOrder.setOrderItemId(orderItem.getOrderItemId());
                workOrder.setProductId(orderItem.getProductId());
                workOrder.setQuantity(batchSize);
                workOrder.setPriority(orderItem.getPriority());
                workOrder.setStatus("待排产");
                workOrder.setPlanStartTime(scheduleStartTime);
                workOrder.setPlanEndTime(parentOrder != null ? convertToLocalDateTime(parentOrder.getDueDate()) : null);
                workOrder.setCreateTime(LocalDateTime.now());
                workOrder.setUpdateTime(LocalDateTime.now());

                workOrders.add(workOrder);

                remaining -= batchSize;
                batchCount++;

                log.debug("生成紧急工单: {} - 产品: {}, 优先级: {}, 数量: {}/{}, 批次: {}",
                        workOrder.getWorkOrderId(), orderItem.getProductId(), orderItem.getPriority(), batchSize,
                        orderItem.getQuantity(), batchCount - 1);
            }

        }

        log.info("紧急优先策略生成工单完成，总数: {}", workOrders.size());
        return workOrders;
    }

    /**
     * 批量生产工单生成策略
     * 将相同产品的订单项合并生成批量工单
     */
    public List<WorkOrder> generateBatchWorkOrders(List<Order> orders, LocalDateTime scheduleStartTime) {
        log.debug("使用批量生产策略生成工单，订单数量: {}", orders.size());

        List<WorkOrder> workOrders = new ArrayList<>();
        AtomicInteger workOrderSequence = new AtomicInteger(1);
        String timeStamp = String.valueOf(System.currentTimeMillis()).substring(7); // 使用毫秒时间戳后6位

        // 按产品分组收集订单项
        java.util.Map<String, List<OrderItem>> productGroups = new java.util.HashMap<>();
        java.util.Map<String, LocalDate> productEarliestDueDate = new java.util.HashMap<>();

        for (Order order : orders) {
            try {
                LambdaQueryWrapper<OrderItem> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(OrderItem::getOrderId, order.getOrderId());
                List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);

                for (OrderItem orderItem : orderItems) {
                    String productId = orderItem.getProductId();

                    productGroups.computeIfAbsent(productId, k -> new ArrayList<>()).add(orderItem);

                    // 记录每个产品的最早截止时间
                    LocalDate currentEarliest = productEarliestDueDate.get(productId);
                    if (order.getDueDate() != null &&
                            (currentEarliest == null || order.getDueDate().isBefore(currentEarliest))) {
                        productEarliestDueDate.put(productId, order.getDueDate());
                    }
                }

            } catch (Exception e) {
                log.error("处理订单 {} 失败: {}", order.getOrderId(), e.getMessage());
            }
        }

        // 为每个产品组生成批量工单
        for (java.util.Map.Entry<String, List<OrderItem>> entry : productGroups.entrySet()) {
            String productId = entry.getKey();
            List<OrderItem> items = entry.getValue();

            // 计算总数量
            int totalQuantity = items.stream().mapToInt(item ->
                    item.getQuantity() != null ? item.getQuantity() : 0).sum();

            // 选择最高优先级
            int highestPriority = items.stream().mapToInt(item ->
                    item.getPriority() != null ? item.getPriority() : 999).min().orElse(5);

            WorkOrder batchWorkOrder = new WorkOrder();
            batchWorkOrder.setWorkOrderId("WOB" + timeStamp + String.format("%03d",
                    workOrderSequence.getAndIncrement()));
            // 设置为第一个订单项的ID（批量工单的代表）
            batchWorkOrder.setOrderItemId(items.get(0).getOrderItemId());
            batchWorkOrder.setProductId(productId);
            batchWorkOrder.setQuantity(totalQuantity);
            batchWorkOrder.setPriority(highestPriority);
            batchWorkOrder.setStatus("已排产");
            batchWorkOrder.setPlanStartTime(scheduleStartTime);
            batchWorkOrder.setPlanEndTime(convertToLocalDateTime(productEarliestDueDate.get(productId)));
            batchWorkOrder.setCreateTime(LocalDateTime.now());
            batchWorkOrder.setUpdateTime(LocalDateTime.now());

            workOrders.add(batchWorkOrder);

            log.debug("生成批量工单: {} - 产品: {}, 总数量: {}, 合并订单项: {}",
                    batchWorkOrder.getWorkOrderId(), productId, totalQuantity, items.size());
        }

        log.info("批量生产策略生成工单完成，总数: {} (合并前订单项数: {})",
                workOrders.size(), productGroups.values().stream().mapToInt(List::size).sum());
        return workOrders;
    }

    /**
     * 机器利用率优先工单生成策略
     * 按工作量大小排序生成工单
     */
    public List<WorkOrder> generateMachineUtilizationWorkOrders(List<Order> orders, LocalDateTime scheduleStartTime) {
        log.debug("使用机器利用率优先策略生成工单，订单数量: {}", orders.size());

        // 使用默认策略生成工单，然后按工作量排序
        List<WorkOrder> workOrders = generateDefaultWorkOrders(orders, scheduleStartTime);

        // 重新设置工单ID为机器利用率前缀
        AtomicInteger workOrderSequence = new AtomicInteger(1);
        String timeStamp = String.valueOf(System.currentTimeMillis()).substring(7); // 使用毫秒时间戳后6位
        for (WorkOrder workOrder : workOrders) {
            workOrder.setWorkOrderId("WOM" + timeStamp + String.format("%03d", workOrderSequence.getAndIncrement()));
        }

        // 按工作量排序（工作量大的优先，有助于提高机器利用率）
        workOrders.sort((wo1, wo2) -> {
            int workload1 = calculateWorkload(wo1);
            int workload2 = calculateWorkload(wo2);

            int workloadCompare = Integer.compare(workload2, workload1); // 工作量大的优先
            if (workloadCompare != 0) {
                return workloadCompare;
            }

            // 工作量相同时按优先级排序
            int priority1 = wo1.getPriority() != null ? wo1.getPriority() : 999;
            int priority2 = wo2.getPriority() != null ? wo2.getPriority() : 999;
            return Integer.compare(priority1, priority2);
        });

        log.info("机器利用率优先策略工单排序完成，总数: {}", workOrders.size());
        return workOrders;
    }

    /**
     * 计算订单的估算工作量
     */
    public int calculateOrderWorkload(Order order) {
        int totalWorkload = 0;
        try {
            // 获取订单项
            LambdaQueryWrapper<OrderItem> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(OrderItem::getOrderId, order.getOrderId());
            List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);

            for (OrderItem item : orderItems) {
                // 获取产品对应的工序
                List<Operation> operations = scheduleDataService.getOperationsByProductId(item.getProductId());
                for (Operation op : operations) {
                    // 获取工序的标准时间
                    int standardTime = op.getStandardTime();
                    // 计算该工序的工作量
                    int workload = item.getQuantity() * standardTime;
                    totalWorkload += workload;
                }
            }
            return totalWorkload;
        } catch (Exception e) {
            log.error("计算订单{}工作量失败: {}", order.getOrderId(), e.getMessage());
            return 100; // 保留默认值作为后备方案
        }
    }

    /**
     * 计算工单的工作量
     */
    private int calculateWorkload(WorkOrder workOrder) {
        int totalWorkload;
        try {
            // 获取产品对应的工序列表
            List<Operation> operations = scheduleDataService.getOperationsByProductId(workOrder.getProductId());

            // 计算各工序总时间
            int totalOperationTime = operations.stream()
                    .mapToInt(op -> op.getStandardTime() != null ? op.getStandardTime() : 0)
                    .sum();

            // 计算总工作量 = 数量 × 总工序时间
            int quantity = workOrder.getQuantity() != null ? workOrder.getQuantity() : 1;
            totalWorkload = quantity * totalOperationTime;

            log.debug("工单 {} 工作量计算: 产品 {} × {} 工序时间 = {}",
                    workOrder.getWorkOrderId(), workOrder.getProductId(),
                    quantity, totalWorkload);

        } catch (Exception e) {
            log.error("计算工单 {} 工作量失败: {}", workOrder.getWorkOrderId(), e.getMessage());
            // 后备方案：使用简化计算
            int quantity = workOrder.getQuantity() != null ? workOrder.getQuantity() : 1;
            totalWorkload = quantity * 60;
        }
        return totalWorkload;
    }

    /**
     * 根据订单项ID查找对应的订单
     */
    private Order findOrderByItemId(List<Order> orders, String orderItemId) {
        for (Order order : orders) {
            try {
                LambdaQueryWrapper<OrderItem> queryWrapper = new LambdaQueryWrapper<>();
                queryWrapper.eq(OrderItem::getOrderId, order.getOrderId());
                List<OrderItem> orderItems = orderItemMapper.selectList(queryWrapper);
                for (OrderItem item : orderItems) {
                    if (item.getOrderItemId().equals(orderItemId)) {
                        return order;
                    }
                }
            } catch (Exception e) {
                log.warn("查找订单项 {} 对应的订单失败: {}", orderItemId, e.getMessage());
            }
        }
        return null;
    }

    /**
     * 将LocalDate转换为LocalDateTime（设为当天的23:59:59）
     */
    private LocalDateTime convertToLocalDateTime(LocalDate localDate) {
        if (localDate == null) {
            return null;
        }
        return localDate.atTime(23, 59, 59);
    }
}

